package pack

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"
	"unicode"
)

type Files struct {
	allFiles []string
}

func NewFiles() *Files {
	return &Files{}
}

func (f *Files) DirFiles(root string) {

	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			fmt.Println("DirFiles func Walk err", err)
			return err
		}
		if !info.IsDir() {
			f.allFiles = append(f.allFiles, path)
		}

		return nil
	})

	if err != nil {
		fmt.Println("DirFiles func return", err)
		panic("pack files err")
	}

}

func (f *Files) GetFiles() []string {
	return f.allFiles
}

func getGoFileName(filename string) (string, string) {
	// 获取文件名和后缀
	base := filepath.Base(filename)
	name := strings.TrimSuffix(base, filepath.Ext(base))
	// 将文件名按下划线分割成多个部分
	parts := strings.Split(name, "_")
	// 将每个部分的首字母大写或小写
	for i := range parts {
		if i == 0 {
			parts[i] = strings.ToLower(parts[i])
		} else {
			parts[i] = strings.ToUpper(parts[i][:1]) + strings.ToLower(parts[i][1:])
		}
	}
	// 拼接驼峰字符串
	camelCase := strings.Join(parts, "") + strings.ToLower(filepath.Ext(base))
	return camelCase + ".go", toUpper(camelCase)
}

func toUpper(str string) string {
	var res string
	for _, v := range strings.Split(str, ".") {
		runes := []rune(v)
		if len(runes) > 0 {
			runes[0] = unicode.ToUpper(runes[0])
		}

		res += string(runes)
	}

	return res
}

func FuncPack(resourcesDir string, jsonDir string, staticDir string) {
	eg := NewFiles()
	eg.DirFiles(jsonDir)
	eg.DirFiles(staticDir)
	fmt.Println("files num", len(eg.GetFiles()))
	allFiles := eg.GetFiles()
	startTime := time.Now()
	for _, name := range allFiles {
		var out io.Writer
		outputFilename, varName := getGoFileName(name)
		packageName := "resources"
		fOut, err := os.Create(resourcesDir + outputFilename)
		if err != nil {
			fmt.Println(err)
			return
		}

		out = fOut

		var in io.Reader
		fIn, err := os.Open(name)
		if err != nil {
			fmt.Println(err)
			return
		}

		in = fIn

		if err = Write(out, in, false, "", packageName, varName); err != nil {
			fmt.Println(err)
			return
		}

		_ = fOut.Close()
		_ = fIn.Close()
	}

	fmt.Println("cost time:", time.Since(startTime).Milliseconds(), "毫秒")
}

func Write(w io.Writer, r io.Reader, compress bool, buildTags string, packageName string, varName string) error {
	if compress {
		compressed := &bytes.Buffer{}
		cw, err := gzip.NewWriterLevel(compressed, gzip.BestCompression)
		if err != nil {
			return err
		}
		if _, err := io.Copy(cw, r); err != nil {
			return err
		}
		cw.Close()
		r = compressed
	}

	bs, err := io.ReadAll(r)
	if err != nil {
		return err
	}

	if _, err := fmt.Fprintln(w, "// Code generated by file2byteslice. DO NOT EDIT."); err != nil {
		return err
	}
	if buildTags != "" {
		if _, err := fmt.Fprintln(w, "\n//go:build "+strings.Join(strings.Split(buildTags, ","), " && ")); err != nil {
			return err
		}
		if _, err := fmt.Fprintln(w, "// +build "+buildTags); err != nil {
			return err
		}
	}
	if _, err := fmt.Fprintln(w, ""); err != nil {
		return err
	}
	if _, err := fmt.Fprintln(w, "package "+packageName); err != nil {
		return err
	}
	if _, err := fmt.Fprintln(w, ""); err != nil {
		return err
	}
	if _, err := fmt.Fprintf(w, "var %s = []byte(%q)\n", varName, string(bs)); err != nil {
		return err
	}
	return nil
}
